package net.siufung.core.utils.token;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import lombok.extern.slf4j.Slf4j;
import net.siufung.core.utils.DateTimeUtil;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Map;

@Slf4j
public class SecureUtil {
	
	static final String CLAIM_KEY_CREATEDATE = "creationTime";

    /**
     * 返回TokenInfo
     * @param claims
     * @param secret
     * @param expireMinutes
     * @return
     * @throws Exception
     */
    public static TokenInfo createToken(Map<String, Object> claims, String secret, int expireMinutes) throws Exception {
        String token = createJWT(claims, secret, expireMinutes);
        return new TokenInfo(token, secret, expireMinutes);
    }

    /**
     * 创建JWT
     * @param claims
     * @param secret
     * @param expireMinutes
     * @return
     * @throws Exception
     */
    public static String createJWT(Map<String, Object> claims, String secret, int expireMinutes) throws Exception {
        return createJWT(StrUtil.EMPTY, claims, secret, expireMinutes);
    }

    /**
     * 创建JWT
     * @param subject
     * @param claims
     * @param secret
     * @param expireMinutes
     * @return
     * @throws Exception
     */
    public static String createJWT(String subject, Map<String, Object> claims, String secret, int expireMinutes) throws Exception {
    	LocalDateTime creationTime = Convert.toLocalDateTime(claims.get(CLAIM_KEY_CREATEDATE));
    	Date expireDate = DateTimeUtil.convertLdtToDate(
    			DateTimeUtil.plus(ObjectUtil.isNull(creationTime)? LocalDateTime.now(): creationTime, 
    					expireMinutes, ChronoUnit.MINUTES));
    	return Jwts.builder()
        		.setSubject(StrUtil.isNotBlank(subject)? subject: StrUtil.EMPTY)
        		.setClaims(claims)
                .setExpiration(expireDate)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    /**
     * 转换成JWT
     * @param token
     * @param secret
     * @return
     */
    public static Claims parseJWT(String token, String secret) {
        return  Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 刷新JWT
     * @param token
     * @param subject
     * @param expireMinutes
     * @param secret
     * @return
     */
    public static String refreshJWT(String token, String subject, int expireMinutes, String secret) {
        String refreshedToken = null;
        try {
            Claims claims = parseJWT(token, secret);
            claims.put(CLAIM_KEY_CREATEDATE, new Date());
            refreshedToken = createJWT(subject, claims, secret, expireMinutes); 
        } catch (Exception e) {
        	log.info(e.getMessage());
        }
        return refreshedToken;
    }


    /**
     * 刷新Token
     * @param tokenInfo
     * @return
     */
    public static TokenInfo refreshToken(TokenInfo tokenInfo) {
        try {
            Claims claims = parseJWT(tokenInfo.getToken(), tokenInfo.getSecret());
            claims.put(CLAIM_KEY_CREATEDATE, new Date());
            tokenInfo.setToken(
                    createJWT(claims, tokenInfo.getSecret(), tokenInfo.getExpireMinutes()));
        } catch (Exception e) {
            log.info(e.getMessage());
            tokenInfo = null;
        }
        return tokenInfo;
    }

    /**
     * 刷新Token
     * @param token
     * @param secret
     * @param expireMinutes
     * @return
     */
    public static TokenInfo refreshToken(String token, String secret, int expireMinutes) {
        TokenInfo tokenInfo = null;
        try {
            Claims claims = parseJWT(token, secret);
            claims.put(CLAIM_KEY_CREATEDATE, new Date());
            token = createJWT(claims, secret, expireMinutes);
            tokenInfo = new TokenInfo(token, secret, expireMinutes);
        } catch (Exception e) {
            log.info(e.getMessage());
        }
        return tokenInfo;
    }

    /**
     * 刷新JWT
     * @param token
     * @param secret
     * @param expireMinutes
     * @return
     */
    public static String refreshJWT(String token, String secret, int expireMinutes) {
        String refreshedToken = null;
        try {
            Claims claims = parseJWT(token, secret);
            claims.put(CLAIM_KEY_CREATEDATE, new Date());
            refreshedToken = createJWT(claims, secret, expireMinutes); 
        } catch (Exception e) {
        	log.info(e.getMessage());
        }
        return refreshedToken;
    }

    /**
     * 获取JWT的失效时间
     * @param token
     * @param secret
     * @return
     */
    public static Date getExpireDate(String token, String secret) {
        Date  expire = null;
        try {
            Claims claims = parseJWT(token, secret);
            expire = claims.getExpiration();
        } catch (Exception e) {
        	log.info(e.getMessage());
        }
        return expire;
    }

    /**
     * 是否超时
     * @param token
     * @param secret
     * @return
     */
    public static Boolean isExpiredJWT(String token, String secret) {
        Date expiration = getExpireDate(token, secret);
        return expiration.before(new Date());
    }
    
    /**
	 * 验证Token是否有效 无效返回TRUE
	 * @param token
	 * @return
	 */
	public static boolean isInvalidJWT(String token, String secret) {
		boolean invalid = Boolean.TRUE;
        try {
            parseJWT(token, secret);
            invalid = Boolean.FALSE;
        } catch (SignatureException | ExpiredJwtException | MalformedJwtException ex) {
            System.out.println(ex.getMessage());
            log.error("jwt invalid error :{}", ex.getMessage());
        }
        return invalid;
    }

//    public static void main(String[] args){
//        String token = "";
//        //System.out.println(SecureUtil.parseJWT(token, "1,1,1,1,1,1,"));
//        String salt = "siufung";
//        String saltMd5 = "6fbe437c74a7b52a60f088ba458032b7";
//        System.out.println(cn.hutool.crypto.SecureUtil.md5(salt));
//        //System.out.println();
//        Long expireMinutes = DateTimeUtil.between(LocalDateTime.now(),
//                LocalDateTimeUtil.parse("2022-06-30 00:00:01", DatePattern.NORM_DATETIME_FORMATTER), ChronoUnit.MINUTES);
//        System.out.println(expireMinutes.intValue());
//        try {
//            Map<String, Object> claims = Maps.newHashMap();
//            claims.put("siufung","chen");
//            String jwtToken = SecureUtil.createJWT(Maps.newHashMap(), saltMd5, expireMinutes.intValue());
//            System.out.println(jwtToken);
//            System.out.println(SecureUtil.isInvalidJWT(jwtToken, saltMd5));
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//
//    }

}
